package com.tqyan.service.transfer;

import com.tqyan.service.redis.RedisManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 限制服务
 * <p> <功能详细描述> </p>
 *
 * @author 陈晨
 * @version 1.0
 * @date 2023/4/21
 */
@Component
@Slf4j
public class LimitService {
    private static final String USER_LOCK = "User:Lock:";
    private static final String USER_LIMIT_SECOND = "User:Limit:second";
    private static final String USER_LIMIT_MINUTE = "User:Limit:minute";
    private static final String USER_LIMIT_MINUTE_10 = "User:Limit:minute10";

    private static final String WECHAT_PAY = "Wechat:Pay:";

    @Autowired
    private RedisManager redisManager;

    /**
     * @description 加锁, 60s超时
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/21 14:45
     */
    public boolean lock(String key) {
        if (StringUtils.isBlank(key)) {
            return true;
        }
        long beginTime = System.currentTimeMillis();
        String lockTime = redisManager.get(USER_LOCK + key);
        if (StringUtils.isBlank(lockTime)
                || !lockTime.matches("[0-9]+")
                || System.currentTimeMillis() - Long.parseLong(lockTime) > 60000) {
            redisManager.set(USER_LOCK + key, System.currentTimeMillis() + "", 60);
//            log.info("[Redis] 加锁, 耗时: {}ms", System.currentTimeMillis() - beginTime);
            return true;
        }
        return false;
    }

    /**
     * @description 解锁
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/21 14:45
     */
    public void unlock(String key) {
        if (StringUtils.isBlank(key)) {
            return;
        }
        long beginTime = System.currentTimeMillis();
        redisManager.del(USER_LOCK + key);
//        log.info("[Redis] 解锁, 耗时: {}ms", System.currentTimeMillis() - beginTime);
    }

    /**
     * @description 会话锁
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/21 15:02
     */
    public boolean lockChat(String openId, Long chatId) {
        return this.lock(openId + ":" + chatId);
    }

    /**
     * @description 会话解锁
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/21 15:02
     */
    public void unlockChat(String openId, Long chatId) {
        this.unlock(openId + ":" + chatId);
    }

    /**
     * @description 限流检查
     * <p>
     *     限流：每5秒提问1次，每分钟提问5次，每10分钟提问20次
     * </p>
     *
     * @author 陈晨
     * @date 2023/4/23 16:43
     */
    public boolean checkLimit(String openId) {
        if (StringUtils.isBlank(openId)) {
            return false;
        }
        // 检查秒锁
        boolean isLimit = redisManager.exists(USER_LIMIT_SECOND + openId);
        if (isLimit) {
            return true;
        }
        redisManager.set(USER_LIMIT_SECOND + openId, "1", 5);
//        log.info("[限流] openId={}, 设置秒锁", openId);

        // 检查分锁
        if (this.setMinuteLimit(openId, USER_LIMIT_MINUTE, 60) > 5) {
            isLimit = true;
        }
        // 检查10分锁
        if (this.setMinuteLimit(openId, USER_LIMIT_MINUTE_10, 600) > 20) {
            isLimit = true;
        }
        return isLimit;
    }

    /**
     * @description 设置分锁
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/23 22:26
     */
    private long setMinuteLimit(String openId, String key, int second) {
        String value = redisManager.get(key + openId);
        if (StringUtils.isNotBlank(value) && !value.contains(":")) {
            value = null;
        }
//        log.info("[限流] key={}, openId={}, value={}, 设置分锁 begin", key, openId, value);
        long limitTime;
        long count;
        if (StringUtils.isBlank(value)) {
            limitTime = System.currentTimeMillis();
            count = 0;
        } else {
            limitTime = Long.parseLong(value.split(":")[0]);
            count = Long.parseLong(value.split(":")[1]);
        }
        int overSecond = (int) ((System.currentTimeMillis() - limitTime) / 1000);
        if (overSecond <= 0) {
            overSecond = second;
            count = 0;
        }
        count += 1;
        value = System.currentTimeMillis() + ":" + count;
        redisManager.set(key + openId, value, overSecond);
        log.info("[限流] key={}, openId={}, value={}, 设置分锁 end", key, openId, value);
        return count;
    }

    /**
     * @description 设置已支付
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/21 14:45
     */
    public void setIsPay(String transactionId) {
        if (StringUtils.isBlank(transactionId)) {
            return;
        }
        redisManager.set(WECHAT_PAY + transactionId, "OK", 300);
    }

    /**
     * @description 是否已支付
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/21 14:45
     */
    public boolean isPay(String transactionId) {
        if (StringUtils.isBlank(transactionId)) {
            return false;
        }
        String result = redisManager.get(WECHAT_PAY + transactionId);
        return StringUtils.isNotBlank(result) && result.equals("OK");
    }

}


